package utils

import (
	"bytes"
	"fmt"
	"gopkg.in/yaml.v3"
	"log"
	"log/slog"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"
)

var (
	Conf *Config
)

func CheckFileExistence(filePath string) bool {
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		return false
	} else if err != nil {
		return false
	}
	return true
}

func GetFileNameFromURL(urlStr string) (string, error) {
	u, err := url.Parse(urlStr)
	if err != nil {
		return "", err
	}

	fileName := u.Path
	fileName = fileName[1:]
	fileName = strings.ReplaceAll(fileName, "/-/", "/")
	fileName = strings.ReplaceAll(fileName, "/", "-")

	return fileName, nil
}

func GetKeys1(m map[string]string) []string {
	// 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率很高
	j := 0
	keys := make([]string, len(m))
	for k := range m {
		keys[j] = k
		j++
	}
	return keys
}

func IsAllEnglishLetters(s string) bool {
	re := regexp.MustCompile(`^[A-Za-z]+$`)
	// 使用正则表达式匹配字符串
	return re.MatchString(s)
}

func getAbsVersion(version string) {

}

func ContainsSpecialKeywords(s string, keywords []string) bool {
	for _, keyword := range keywords {
		if strings.Contains(strings.ToLower(s), keyword) {
			return true
		}
	}

	return false
}

func ParseConfig(filePath *string) *Config {
	if _, err := os.Stat(*filePath); os.IsNotExist(err) {
		slog.Error("找不到配置文件", "path", *filePath)
		os.Exit(1)
	}

	data, err := os.ReadFile(*filePath)
	if err != nil {
		slog.Error("配置文件读取失败", "err", err)
		os.Exit(1)
	}

	conf := Config{}
	err = yaml.Unmarshal(data, &conf)
	if err != nil {
		slog.Error("配置文件解析失败", "err", err)
		os.Exit(1)
	}

	return &conf
}

func ContainsLetter(s string) bool {
	re := regexp.MustCompile(`[a-zA-Z]`)
	return re.FindString(s) != ""
}

// isValidChar 检查字符是否合法
func isValidChar(r rune) bool {
	// 保留的 Windows 设备名
	reservedNames := []string{"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
		"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}

	// ASCII 控制字符（0-31）
	if r < 32 {
		return false
	}
	// 非法字符
	if strings.ContainsRune("\\/:*?\"<>|\x00", r) {
		return false
	}
	// 检查是否是保留文件名的一部分
	for _, name := range reservedNames {
		if strings.ToLower(string(r)+strings.Repeat(" ", len(name)-1)) == strings.ToLower(name[:1]) {
			return false
		}
	}
	return true
}

// SanitizeFileName sanitizeFileName 将字符串转换为合法的文件名
func SanitizeFileName(input string) string {
	if strings.Contains(input, string(filepath.Separator)) {
		input = filepath.Base(input)
	}

	// 替换非法字符
	re := regexp.MustCompile(`[\\/:*?\"<>|\x00-\x1F]+`)
	sanitized := re.ReplaceAllString(input, "_")

	// 去除前导和尾随的点以及连续的多个点
	sanitized = strings.Trim(sanitized, ".")
	sanitized = regexp.MustCompile(`\.+`).ReplaceAllString(sanitized, ".")

	// 转换为小写（可选，如果希望文件名不区分大小写）
	sanitized = strings.ToLower(sanitized)

	// 处理文件名长度（如果需要）
	if len(sanitized) > 255 {
		sanitized = sanitized[:255]
	}

	// 去除文件名末尾的空格（可选）
	sanitized = strings.TrimSpace(sanitized)

	// 确保文件名不为空
	if sanitized == "" {
		sanitized = "file"
	}

	// 构建合法的文件名
	var result []rune
	for _, r := range sanitized {
		if isValidChar(r) {
			result = append(result, r)
		} else {
			result = append(result, '_') // 或者使用 '-'
		}
	}

	return string(result)
}

func ParseVersion(pname string, ver string) (string, string) {
	if strings.Contains(ver, "npm:@") {
		ver = strings.ReplaceAll(ver, "npm:@", "")
		verSplit := strings.Split(ver, "@")
		if len(verSplit) > 0 {
			name := verSplit[0]
			ver = verSplit[1]
			return fmt.Sprintf("@%s", name), ver
		}
	} else if strings.Contains(ver, "npm:") {
		ver = strings.ReplaceAll(ver, "npm:", "")
		verSplit := strings.Split(ver, "@")
		if len(verSplit) > 0 {
			name := verSplit[0]
			ver = verSplit[1]
			return name, ver
		}
	} else if strings.Contains(ver, "/") {
		return pname, ""
	} else if strings.Contains(ver, "*") {
		return pname, ""
	} else if strings.Contains(ver, "github") {
		return pname, ""
	} else if strings.Contains(ver, "git") {
		return pname, ""
	} else if strings.Contains(ver, "link") {
		return pname, ""
	} else if strings.Contains(ver, "file") {
		return pname, ""
	}

	return pname, ver
}

func WriteLog(name, msg string) {
	dir, err := filepath.Abs(".")
	if err != nil {
		return
	}

	logFilePath := fmt.Sprintf("%s/%s_%s.log", dir, name, time.Now().Format("2006-01-02"))
	file, _ := os.OpenFile(logFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	_, _ = file.WriteString(fmt.Sprintf("%s\n", msg))
	defer file.Close()
}

func GetCurrentDir() string {
	dir, err := filepath.Abs(".")
	if err != nil {
		log.Fatal(err)
	}

	return dir
}

func SaveFile(filename string, buf bytes.Buffer) {
	err := os.WriteFile(filename, buf.Bytes(), 0755)
	if err != nil {
		fmt.Println("Error creating the file:", err)
		return
	}
}
